package bll

import (
  "context"
  "fmt"
  "go-micro.dev/v4/client"
  "reflect"
  "unsafe"

  "gitlab.local/backend/proto/dto"
  "manager/client/grpc"
  "manager/errors"
  SignalPo "manager/model/signal"
  "manager/utils"
)

type signal struct {
}

var Signal = &signal{}

// SendCmdToDevice 给设备端下发指令
func (s *signal) SendCmdToDevice(ctx context.Context, in *SignalPo.CommandReq) error {
  var (
    err error
  )

  //  查询sn码
  sn, err := Ebike.GetSn(in.EbikeId)
  if err != nil {
    return fmt.Errorf("get sn code failed")
  }

  cmd := &dto.CommandRequest{
    Sn:  sn,
    Cmd: dto.CmdType(in.Cmd),
  }

  fmt.Println("SendCmdToDevice  bikeId:", in.EbikeId, "data:", utils.ToJsonString(cmd))
  // 执行指令
  err = RpcCall(sn, func(addr string, err error) error {
    if err != nil {
      return err
    }

    _, err = grpc.Cmd.Command(ctx, cmd, func(options *client.CallOptions) {
      options.Address = []string{addr}
    })
    if err != nil {
      return fmt.Errorf("execute command failed")
    }
    return err
  })

  return nil
}

// SendToggleToDevice 给设备端下发指令
func (s *signal) SendToggleToDevice(ctx context.Context, in *SignalPo.ToggleReq) error {
  //  查询sn码
  sn, err := Ebike.GetSn(in.EbikeId)
  if err != nil {
    return fmt.Errorf("get sn code failed")
  }

  // 执行指令
  in.Sn = sn
  value := (*dto.SwitchRequest)(unsafe.Pointer(uintptr(unsafe.Pointer(in)) + uintptr(8)))

  fmt.Println("SendToggleToDevice  bikeId:", in.EbikeId, " data:", utils.ToJsonString(value))

  err = RpcCall(sn, func(addr string, err error) error {
    if err != nil {
      return err
    }

    _, err = grpc.Cmd.Switch(ctx, value, func(options *client.CallOptions) {
      options.Address = []string{addr}
    })
    if err != nil {
      return fmt.Errorf("execute switch command failed")
    }
    return err
  })

  return nil
}

// SendMsgToDevice 发送信息给设备端
func (s *signal) SendMsgToDevice(ctx context.Context, in *SignalPo.MessageReq) error {
  //  查询sn码
  sn, err := Ebike.GetSn(in.EbikeId)
  if err != nil {
    return fmt.Errorf("get sn code failed")
  }

  // 执行指令
  in.Sn = sn
  value := (*dto.SettingRequest)(unsafe.Pointer(uintptr(unsafe.Pointer(in)) + uintptr(8)))

  fmt.Println("SendMsgToDevice bikeId:", in.EbikeId, " data:", utils.ToJsonString(value))
  err = RpcCall(sn, func(addr string, err error) error {
    if err != nil {
      return err
    }

    _, err = grpc.Cmd.Setting(ctx, value, func(options *client.CallOptions) {
      options.Address = []string{addr}
    })
    if err != nil {
      return fmt.Errorf("execute Setting command failed")
    }
    return err
  })

  return nil
}

// GetMsgFromDevice 查询设备信息
func (s *signal) GetMsgFromDevice(ctx context.Context, in *SignalPo.GetMessageReq) (interface{}, error) {

  //  查询sn码
  sn, err := Ebike.GetSn(in.EbikeId)
  if err != nil {
    return nil, fmt.Errorf("get sn code failed")
  }

  rtype := reflect.TypeOf(grpc.Cmd)
  rvalue := reflect.ValueOf(grpc.Cmd)
  for i := 0; i < rvalue.NumMethod(); i++ {
    name := rtype.Method(i).Name
    if name != in.Cmd {
      continue
    }

    // 执行指令
    params := []reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(&SignalPo.BaseSearchRequest{Sn: sn})}

    fmt.Println("SendMsgToDevice bikeId:", in.EbikeId, " sn:", sn)
    results := rvalue.Method(i).Call(params)
    if len(results) == 2 && results[1].Interface() == nil {
      return results[0].Interface(), nil
    }

    // 错误处理
    if results[1].Interface() != nil {
      return nil, results[1].Interface().(error)
    }
  }

  return nil, errors.New(fmt.Sprintf("not exist rpc handler name:%v", in.Cmd))
}

func (s *signal) ReactiveCmd(ctx context.Context, in *dto.ReactiveRequest) error {
  return RpcCall(in.Sn, func(addr string, err error) error {
    if err != nil {
      return err
    }

    _, err = grpc.Cmd.Reactive(ctx, in, func(options *client.CallOptions) {
      options.Address = []string{addr}
    })
    return err
  })
}
